package cn.linstudy;

import cn.hutool.json.JSONUtil;
import com.alibaba.fastjson.JSON;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.flowable.engine.HistoryService;
import org.flowable.engine.RepositoryService;
import org.flowable.engine.RuntimeService;
import org.flowable.engine.history.HistoricProcessInstance;
import org.flowable.engine.repository.Deployment;
import org.flowable.engine.repository.ProcessDefinition;
import org.flowable.engine.runtime.Execution;
import org.flowable.engine.runtime.ProcessInstance;
import org.flowable.idm.api.Group;
import org.flowable.idm.api.User;
import org.flowable.task.api.Task;
import org.flowable.task.api.history.HistoricTaskInstance;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.HashMap;
import java.util.List;
import java.util.Map;

@RestController
@RequiredArgsConstructor
@Slf4j
@RequestMapping("/api/process")
public class ProcessController {

    @Autowired
    private RepositoryService repositoryService;
    @Autowired
    private RuntimeService runtimeService;
    @Autowired
    private HistoryService historyService;
    @Autowired
    private org.flowable.engine.TaskService taskService;
    @Autowired
    private org.flowable.engine.IdentityService identityService;

    /**
     * 部署流程模型.
     *
     * @return 流程key
     */
    @PostMapping("/deploy")
    public ResponseEntity<Object> createProcessDef() {
        Deployment deployment = null;
        try {
            deployment = repositoryService
                    .createDeployment()
                    .addClasspathResource("leave_approval3.bpmn20.xml")
                    .deploy();
            log.info("部署成功:{}", deployment.getId());
        } catch (Exception e) {
            e.printStackTrace();
        }
        /*
         * @Date: 2021/10/17 23:40
         * Step 3: 启动流程，创建实例
         */
        String processDefinitionKey = "leave_approval";//流程定义的key,对应请假的流程图
        String businessKey = "schoolleave";//业务代码，根据自己的业务用

        /*
         * @Date: 2021/10/17 23:40
         * Step 4: 查询指定流程所有启动的实例列表
         * 列表，或 分页 删除
         */
        List<ProcessInstance> processInstanceList = runtimeService.createProcessInstanceQuery().processDefinitionKey(processDefinitionKey).list();
        for(ProcessInstance pi: processInstanceList){
            runtimeService.deleteProcessInstance(pi.getProcessInstanceId(), "流程实例重置完成"); //删除实例
        }
        Map<String, Object> variablesDefinition = new HashMap<>();//流程变量，可以自定义扩充
        ProcessInstance processInstance = runtimeService.startProcessInstanceByKey(processDefinitionKey, businessKey, variablesDefinition);
        log.info("启动成功:{}", processInstance.getId());
        //5.返回部署的流程id
        return new ResponseEntity<>(deployment.getId(), HttpStatus.OK);
    }


    /**
     * 部署流程模型.
     *
     * @return 流程key
     */
    @PostMapping("/jcDeploy")
    public ResponseEntity<Object> createProcessDefForJc() {
        Deployment deployment = null;
        try {
            deployment = repositoryService
                    .createDeployment()
                    .addClasspathResource("jc_leave_approval.bpmn20.xml")
                    .deploy();
            log.info("部署成功:{}", deployment.getId());
        } catch (Exception e) {
            e.printStackTrace();
        }
        /*
         * @Date: 2021/10/17 23:40
         * Step 3: 启动流程，创建实例
         */
        String processDefinitionKey = "jc_leave_approval";//流程定义的key,对应请假的流程图
        String businessKey = "schoolleave";//业务代码，根据自己的业务用

        /*
         * @Date: 2021/10/17 23:40
         * Step 4: 查询指定流程所有启动的实例列表
         * 列表，或 分页 删除
         */
        List<ProcessInstance> processInstanceList = runtimeService.createProcessInstanceQuery().processDefinitionKey(processDefinitionKey).list();
        for(ProcessInstance pi: processInstanceList){
            runtimeService.deleteProcessInstance(pi.getProcessInstanceId(), "流程实例重置完成"); //删除实例
        }
        Map<String, Object> variablesDefinition = new HashMap<>();//流程变量，可以自定义扩充
        ProcessInstance processInstance = runtimeService.startProcessInstanceByKey(processDefinitionKey, businessKey, variablesDefinition);
        log.info("启动成功:{}", processInstance.getId());
        //5.返回部署的流程id
        return new ResponseEntity<>(deployment.getId(), HttpStatus.OK);
    }

    /**
     * 部署流程模型.
     *
     * @return 流程key
     */
    @PostMapping("/execute")
    public ResponseEntity<Object> justForTestProcess() {
        Deployment deployment = null;
        try {
            deployment = repositoryService
                    .createDeployment()
                    .addClasspathResource("leave_approval3.bpmn20.xml")
                    .deploy();
            log.info("部署成功:{}", deployment.getId());
        } catch (Exception e) {
            e.printStackTrace();
        }

        /*
         * @Date: 2021/10/17 23:40
         * Step 2: 查询部署的流程定义
         */
        List<ProcessDefinition> list = repositoryService.createProcessDefinitionQuery().processDefinitionKey("leave_approval").list();
        List<ProcessDefinition> pages = repositoryService.createProcessDefinitionQuery().processDefinitionKey("leave_approval").listPage(1, 30);

        /*
         * @Date: 2021/10/17 23:40
         * Step 3: 启动流程，创建实例
         */
        String processDefinitionKey = "leave_approval";//流程定义的key,对应请假的流程图
        String businessKey = "schoolleave";//业务代码，根据自己的业务用
        Map<String, Object> variablesDefinition = new HashMap<>();//流程变量，可以自定义扩充
        ProcessInstance processInstance = runtimeService.startProcessInstanceByKey(processDefinitionKey, businessKey, variablesDefinition);
        log.info("启动成功:{}", processInstance.getId());

        createGroup("stu_group","学生组");
        createGroup("te_group","老师组");
        createGroup("mte_group","校长组");

        /*
         * @Date: 2021/10/17 23:40
         * Step 4: 查询指定流程所有启动的实例列表
         * 列表，或 分页 删除
         */
        List<Execution> executions = runtimeService.createExecutionQuery().processDefinitionKey("leave_approval").list();
        List<Execution> executionPages = runtimeService.createExecutionQuery().processDefinitionKey("leave_approval").listPage(1, 30);
//        runtimeService.deleteProcessInstance(processInstanceId, deleteReason); //删除实例

        /*
         * @Date: 2021/10/17 23:40
         * Step 5: 学生查询可以操作的任务,并完成任务
         */
        String candidateGroup = "stu_group"; //候选组 xml文件里面的 flowable:candidateGroups="stu_group"
        List<Task> taskList = taskService.createTaskQuery().taskCandidateGroup(candidateGroup).orderByTaskCreateTime().desc().list();
        for (Task task : taskList) {
            // 申领任务
            taskService.claim(task.getId(), "my");
            // 完成
            taskService.complete(task.getId());
        }

        /*
         * @Date: 2021/10/17 23:40
         * Step 6: 老师查询可以操作的任务,并完成任务
         */
        String candidateGroupTe = "te_group"; //候选组 xml文件里面的 flowable:candidateGroups="te_group"
        List<Task> taskListTe = taskService.createTaskQuery().taskCandidateGroup(candidateGroupTe).orderByTaskCreateTime().desc().list();
        for (Task task : taskListTe) {
            // 申领任务
            taskService.claim(task.getId(), "myte");
            // 完成
            Map<String, Object> variables = new HashMap<>();
            variables.put("command", "agree"); //携带变量，用于网关流程的条件判定，这里的条件是同意
            taskService.complete(task.getId(), variables);
        }

        /*
         * @Date: 2021/10/17 23:40
         * Step 6: 老师查询可以操作的任务,并完成任务
         */
        String candidateGroupMte = "mte_group"; //候选组 xml文件里面的 flowable:candidateGroups="mte_group"
        List<Task> taskListMte = taskService.createTaskQuery().taskCandidateGroup(candidateGroupMte).orderByTaskCreateTime().desc().list();
        for (Task task : taskListMte) {
            // 申领任务
            taskService.claim(task.getId(), "myMte");
            // 完成
            Map<String, Object> variables = new HashMap<>();
            variables.put("command", "agree"); //携带变量，用于网关流程的条件判定，这里的条件是同意
            taskService.complete(task.getId(), variables);
        }

        /*
         * @Date: 2021/10/18 0:17
         * Step 7: 历史查询，因为一旦流程执行完毕，活动的数据都会被清空，上面查询的接口都查不到数据，但是提供历史查询接口
         */
        // 历史流程实例
        List<HistoricProcessInstance> historicProcessList = historyService.createHistoricProcessInstanceQuery().processDefinitionKey("leave_approval").list();
        // 历史任务
        List<HistoricTaskInstance> historicTaskList = historyService.createHistoricTaskInstanceQuery().processDefinitionKey("leave_approval").list();
        // 如果在数据库配置了分组和用户，还会用到
        List<User> users = identityService.createUserQuery().list();    //用户查询，用户id对应xml 里面配置的用户
        List<Group> groups = identityService.createGroupQuery().list(); //分组查询，分组id对应xml 里面配置的分组 如 stu_group，te_group 在表里是id的值

        // 另外，每个查询后面都可以拼条件，内置恁多查询，包括模糊查询，大小比较都有
        return new ResponseEntity<>(deployment.getId(), HttpStatus.OK);
    }


    /**
     * 查询当前流程节点信息，并进行相应审批操作；返回操作的结果;
     * stu_group:stu1,stu2,stu3
     * tea_group:tea1,tea2,tea3
     * mte_group:mte1,mte2,mte3
     * auditResult:"agree","refuse"
     * @param userId 用户id
     * @param candidateGroup 归属的候选组
     * @param auditResult  审核的原因
     * @return userTaskInfo 当前用户任务详细信息
     */
    @PostMapping("/executeProcess")
    public ResponseEntity<Object> executeProcess(String userId,String candidateGroup,String auditResult,boolean resetFlag) {

        /*
         * @Date: 2021/10/17 23:40
         * Step 2: 查询部署的流程定义
         */
        List<ProcessDefinition> list = repositoryService.createProcessDefinitionQuery().processDefinitionKey("leave_approval").list();
        List<ProcessDefinition> pages = repositoryService.createProcessDefinitionQuery().processDefinitionKey("leave_approval").listPage(1, 30);


        createUserToGroup("stu1","stu_group","学生1");
        createUserToGroup("stu2","stu_group","学生2");
        createUserToGroup("stu3","stu_group","学生3");
        createUserToGroup("tea1","te_group","老师1");
        createUserToGroup("tea2","te_group","老师2");
        createUserToGroup("tea3","te_group","老师3");
        createUserToGroup("mte1","mte_group","校长1");
        createUserToGroup("mte2","mte_group","校长2");
        createUserToGroup("mte3","mte_group","校长3");

        if(StringUtils.equals(candidateGroup,"stu_group")){
            List<Task> taskList = taskService.createTaskQuery().taskCandidateGroup(candidateGroup).orderByTaskCreateTime().desc().list();
            log.info("代办任务数量【{}】,userId => {},todo taskInfo =>{} ",taskList.size(),userId,JSONUtil.toJsonStr(taskList));
            for (Task task : taskList) {
                // 申领任务
                taskService.claim(task.getId(), userId);
                // 完成
                taskService.complete(task.getId());
            }
        }

        if(StringUtils.equals(candidateGroup,"te_group")){
            List<Task> taskListTe = taskService.createTaskQuery().taskCandidateGroup(candidateGroup).orderByTaskCreateTime().desc().list();
            log.info("代办任务数量【{}】,userId => {},todo taskInfo =>{} ",taskListTe.size(),userId,JSONUtil.toJsonStr(taskListTe));
            for (Task task : taskListTe) {
                // 申领任务
                taskService.claim(task.getId(), userId);
                // 完成
                Map<String, Object> variables = new HashMap<>();
                variables.put("command", auditResult); //携带变量，用于网关流程的条件判定，这里的条件是同意
                taskService.complete(task.getId(), variables);
            }
        }

        if(StringUtils.equals(candidateGroup,"mte_group")){
            List<Task> taskListMte = taskService.createTaskQuery().taskCandidateGroup(candidateGroup).orderByTaskCreateTime().desc().list();
            log.info("代办任务数量【{}】,userId => {},todo taskInfo =>{} ",taskListMte.size(),userId,JSONUtil.toJsonStr(taskListMte));
            for (Task task : taskListMte) {
                // 申领任务
                taskService.claim(task.getId(), userId);
                // 完成
                Map<String, Object> variables = new HashMap<>();
                variables.put("command", auditResult); //携带变量，用于网关流程的条件判定，这里的条件是同意
                taskService.complete(task.getId(), variables);
            }
        }




        /*
         * @Date: 2021/10/18 0:17
         * Step 7: 历史查询，因为一旦流程执行完毕，活动的数据都会被清空，上面查询的接口都查不到数据，但是提供历史查询接口
         */
        // 历史流程实例
        List<HistoricProcessInstance> historicProcessList = historyService.createHistoricProcessInstanceQuery().processDefinitionKey("leave_approval").list();
        // 历史任务
        List<HistoricTaskInstance> historicTaskList = historyService.createHistoricTaskInstanceQuery().processDefinitionKey("leave_approval").list();
        // 如果在数据库配置了分组和用户，还会用到
        List<User> users = identityService.createUserQuery().list();    //用户查询，用户id对应xml 里面配置的用户
        List<Group> groups = identityService.createGroupQuery().list(); //分组查询，分组id对应xml 里面配置的分组 如 stu_group，te_group 在表里是id的值


        //返回当前用户的task节点信息;
        List<HistoricTaskInstance> userHistoricTaskList = historyService.createHistoricTaskInstanceQuery().processDefinitionKey("leave_approval").taskInvolvedUser(userId).list();
        log.info("userId => {},taskInfo => {}",userId, JSONUtil.toJsonStr(userHistoricTaskList));


        return new ResponseEntity<>(userHistoricTaskList, HttpStatus.OK);
    }


    /**
     * 查询当前流程节点信息，并进行相应审批操作；返回操作的结果;
     * department_group:emp1,emp2,emp3
     * department_leader:songyi
     * company_leader:syy
     * auditResult:"agree","refuse"
     * @param userId 用户id
     * @param candidateGroup 归属的候选组
     * @param auditResult  审核的原因
     * @return userTaskInfo 当前用户任务详细信息
     */
    @PostMapping("/jcExecuteProcess")
    public ResponseEntity<Object> jcExecuteProcess(String userId,String candidateGroup,String auditResult,String days) {



        createGroup("department_group","数智工业部");
        createGroup("department_leader","部门经理");
        createGroup("company_leader","公司副总");
        createUserToGroup("emp1","department_group","dirk1");
        createUserToGroup("emp2","department_group","dirk2");
        createUserToGroup("emp3","department_group","dirk3");
        createUserToGroup("songyi","department_leader","宋逸");
        createUserToGroup("syy","company_leader","石益宇");

        if(StringUtils.equals(candidateGroup,"department_group")){
            List<Task> taskList = taskService.createTaskQuery().taskCandidateGroup(candidateGroup).orderByTaskCreateTime().desc().list();
            log.info("代办任务数量【{}】,userId => {},todo taskInfo =>{} ",taskList.size(),userId,JSONUtil.toJsonStr(taskList));
            for (Task task : taskList) {
                // 申领任务
                taskService.claim(task.getId(), userId);
                Map<String,Object> variables = new HashMap<>();
                variables.put("days",days);
                // 完成
                taskService.complete(task.getId(),variables);
            }
        }

        if(StringUtils.equals(candidateGroup,"department_leader")){
            List<Task> taskListTe = taskService.createTaskQuery().taskCandidateGroup(candidateGroup).orderByTaskCreateTime().desc().list();
            log.info("代办任务数量【{}】,userId => {},todo taskInfo =>{} ",taskListTe.size(),userId,JSONUtil.toJsonStr(taskListTe));
            for (Task task : taskListTe) {
                // 申领任务
                taskService.claim(task.getId(), userId);
                // 完成
                Map<String, Object> variables = new HashMap<>();
                variables.put("command", auditResult); //携带变量，用于网关流程的条件判定，这里的条件是同意
                taskService.complete(task.getId(), variables);
            }
        }

        if(StringUtils.equals(candidateGroup,"company_leader")){
            List<Task> taskListMte = taskService.createTaskQuery().taskCandidateGroup(candidateGroup).orderByTaskCreateTime().desc().list();
            log.info("代办任务数量【{}】,userId => {},todo taskInfo =>{} ",taskListMte.size(),userId,JSONUtil.toJsonStr(taskListMte));
            for (Task task : taskListMte) {
                // 申领任务
                taskService.claim(task.getId(), userId);
                // 完成
                Map<String, Object> variables = new HashMap<>();
                variables.put("command", auditResult); //携带变量，用于网关流程的条件判定，这里的条件是同意
                taskService.complete(task.getId(), variables);
            }
        }




        /*
         * @Date: 2021/10/18 0:17
         * Step 7: 历史查询，因为一旦流程执行完毕，活动的数据都会被清空，上面查询的接口都查不到数据，但是提供历史查询接口
         */
        // 历史流程实例
        List<HistoricProcessInstance> historicProcessList = historyService.createHistoricProcessInstanceQuery().processDefinitionKey("jc_leave_approval").list();
        // 历史任务
        List<HistoricTaskInstance> historicTaskList = historyService.createHistoricTaskInstanceQuery().processDefinitionKey("jc_leave_approval").list();
        // 如果在数据库配置了分组和用户，还会用到
        List<User> users = identityService.createUserQuery().list();    //用户查询，用户id对应xml 里面配置的用户
        List<Group> groups = identityService.createGroupQuery().list(); //分组查询，分组id对应xml 里面配置的分组 如 stu_group，te_group 在表里是id的值


        //返回当前用户的task节点信息;
        List<HistoricTaskInstance> userHistoricTaskList = historyService.createHistoricTaskInstanceQuery().processDefinitionKey("jc_leave_approval").taskInvolvedUser(userId).list();
        log.info("userId => {},taskInfo => {}",userId, JSONUtil.toJsonStr(userHistoricTaskList));


        return new ResponseEntity<>(userHistoricTaskList, HttpStatus.OK);
    }

    /**
     * 创建新用户组
     * @param groupId 组ID（唯一标识）
     * @param groupName 组名称
     */
    private void createGroup(String groupId, String groupName) {
        // 检查是否已存在同名组
        Group existingGroup = identityService.createGroupQuery()
                .groupId(groupId)
                .singleResult();

        if (existingGroup == null) {
            Group group = identityService.newGroup(groupId);
            group.setName(groupName);
            group.setType("assignment"); // 类型可选，如权限组/角色组
            identityService.saveGroup(group);
        } else {
            return;
        }
    }

    /**
     * 创建用户到组里
     */
    private void createUserToGroup(String userId, String groupId,String userName) {
        // 检查是否已存在同名组
        User existingUser = identityService.createUserQuery().memberOfGroup(groupId).userId(userId).singleResult();

        if (existingUser == null) {
            User user = identityService.newUser(userId);
            user.setId(userId);
            user.setDisplayName(userName);
            user.setFirstName(userName);
            user.setLastName(userName);
            identityService.saveUser(user);
            identityService.createMembership(userId,groupId);
        } else {
            return;
        }
    }



    
}